//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ER = Microsoft.Research.DataLayer;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using Microsoft.Research.eResearch.Common.Logging;
using SH = Microsoft.Hpc.Scheduler;

namespace Microsoft.Research.eResearch.TridentScheduleCommon
{
    [Serializable]
    public class WrongSchedulerConfigException : Exception
    {
        public WrongSchedulerConfigException()
            : base()
        {

        }
        public WrongSchedulerConfigException(string exceptionMessage)
            : base(exceptionMessage)
        {

        }
        public WrongSchedulerConfigException(string exceptionMessage, Exception exp)
            : base(exceptionMessage, exp)
        {

        }

        protected WrongSchedulerConfigException(
            SerializationInfo serializationInfo,
            StreamingContext streamingContext)
            : base(serializationInfo, streamingContext)
        {

        }
    }
    /// <summary>
    /// Event arguments for job notifications for UI components
    /// </summary>
    public class WFLauchEventArgs : EventArgs
    {
        public WFLauchEventArgs()
            : base()
        {
        }

        public WFLauchEventArgs(string wfName)
            : base()
        {
            workflowName = wfName;
        }
        /// <summary>
        /// Data member holding the workflow lauch message
        /// </summary>
        public string WorkflowName
        {
            set
            {
                workflowName = value;
            }
            get
            {
                return workflowName;
            }

        }
        private string workflowName;

    }
    /// <summary>
    /// Scheduler interface for getting the status 
    /// </summary>
    public interface ITridentScheduleStatus
    {
        /// <summary>
        /// Gets the schedule status from Process exit status/HPC job status
        /// </summary>
        /// <param name="job"></param>
        /// <returns></returns>
        ER.JobStatus GetScheduleStatus(ER.Job job);


    }

    /// <summary>
    /// Scheduler interface, which Hpc or server version should implement
    /// </summary>
    public interface ITridentScheduler : ILoggable
    {
        void Initialize(string executionProcName,
                                        ER.Connection registryConnection,
                                        EventHandler exitEvent,
                                        EventHandler<WFLauchEventArgs> launchWorkflowUIHandler);


        /// <summary>
        /// Process the list of jobs provided with the scheduling logic implemented
        /// inside the module
        /// </summary>
        /// <param name="jobs">Registry jobs scheduled for this particular instance</param>
        void ProcessJobs(bool showConsole, Collection<ER.Job> jobs, ER.Machine machine);

        /// <summary>
        /// Update the registry connection to schedulers after reconnect
        /// </summary>
        /// <param name="registryConn"> registry handle</param>
        void UpdateRegistryConnection(ER.Connection registryConnection);
    };

    /// <summary>
    /// Interface which any custom Hpc schedule engine should implement
    /// </summary>
    public interface ITridentHpcScheduleEngine
    {
        /// <summary>
        /// Before calling the find node scheduler shall call this interface method to make the engine 
        /// ready to accept calls for different jobs
        /// </summary>
        /// <param name="tridentJob"></param>
        /// <param name="currentMachine"></param>
        /// <param name="nodes"></param>
        void PreScheduleJob(ER.Job tridentJob, ER.Machine currentMachine, string[] nodes);

        /// This method should be overridden to provide the custom schedule logic 
        /// </summary>
        /// <param name="tridentJob"></param>
        /// <returns> Node names list to which the specified job can be scheduled</returns>
        string[] FindNodes(ER.Job tridentJob, ER.Machine currentMachine, string[] nodes);


        /// <summary>
        /// Post schedule job to process anything special after scheduling
        /// </summary>
        /// <param name="tridentJob"></param>
        /// <param name="currentMachine"></param>
        /// <param name="nodes"></param>
        void PostScheduleJob(ER.Job tridentJob, ER.Machine currentMachine, string[] nodes);

    };

    /// <summary>
    /// Interface which any custom server schedule engine should implement
    /// </summary>
    public interface ITridentServerScheduleEngine
    {
        /// <summary>
        /// 
        /// </summary>
        void Initialize();

        /// <summary>
        /// 
        /// </summary>
        /// <param name="tridentJob"></param>
        /// <param name="currentMachine"></param>
        /// <param name="nodes"></param>
        void PreScheduleJob(ER.Job tridentJob, ER.Machine currentMachine);

        /// <summary>
        /// If this function returns false job scheduling will be stopped
        /// </summary>
        /// <param name="tridentJob"></param>
        /// <param name="currentMachine"></param>
        bool CustomizeJob(ER.Job tridentJob, ER.Machine currentMachine);

        /// <summary>
        /// Scheduler shall call this interface method to do post processing 
        /// of a job by the scheduler engine.
        /// </summary>
        /// <param name="tridentJob"></param>
        /// <param name="currentMachine"></param>
        /// <param name="node"></param>
        void PostScheduleJob(ER.Job tridentJob, ER.Machine currentMachine);
    };

}
